<?php

namespace App\Structs;

use App\Enums\OrderItemType;
use App\Models\Member;
use App\Models\Order;
use App\Models\Table;

class OrderBill implements \JsonSerializable
{
    /**
     * @var OrderBillItem[]
     */
    public $items = [];

    public $originTotalMoney;

    public $totalMoney;

    public $discountMoney;

    public $member = null;

    private $memberReseted = false;

    public function setMember(Member $member)
    {
        if ($this->memberReseted)
            return ;

        if (empty($this->member) && !$this->memberReseted) {
            $this->member = $member;
        } else {

            if ($this->member->id != $member->id) {

                $this->member = null;
                $this->memberReseted = true;
            }
        }
    }

    public function discount($money)
    {
        $this->discountMoney += $money;
        $this->totalMoney = $this->originTotalMoney - $this->discountMoney;
    }

    public function getTotalMoney()
    {
        if (empty($this->items))
            return 0;

        $totalMoney = 0;
        foreach ($this->items as $item) {
            $totalMoney += $item->getTotalMoney();
        }

        $this->originTotalMoney = $totalMoney;
        $this->totalMoney = $totalMoney - $this->discountMoney;

        return $totalMoney;
    }

    public function addOrder(Order $order, $finishDate = null)
    {
        if (!empty($order->member))
            $this->setMember($order->member);

        if (is_null($finishDate)) {
            $finishDate = now();
        }

        $tableItem = $order->getTableItem();
        if (empty($tableItem)) {

            $itemIndex = $this->getNoTableItemIndex();
        } else {

            /**
             * @var Table $table
             */
            $table = $tableItem->table;
            $table->tableType;
            $itemIndex = $this->getOrAddTableIndexInItems($table);

            if (empty($tableItem->end_at)) {

                $tableTotalMoney = $tableItem->getTotalMoney($finishDate);
                $tableItem->end_at = $finishDate;
                $tableItem->money = $tableTotalMoney;
                $tableItem->origin_money = $tableTotalMoney;
                $order->money += $tableTotalMoney;
                $order->origin_money += $tableTotalMoney;
            }
        }

        if (!empty($tableItem))
           $this->items[$itemIndex]->items[] = $tableItem;

        foreach ($order->items as $item) {

            if ($item->type == OrderItemType::Table)
                continue;
            $this->items[$itemIndex]->items[] = $item;
        }

        $this->items[$itemIndex]->orders[] = $order;

        $this->getTotalMoney();
    }

    private function getNoTableItemIndex()
    {
        foreach ($this->items as $k => $item) {
            if (is_null($item->table))
                return $k;
        }

        $this->items[] = new OrderBillItem();
        return count($this->items) - 1;
    }

    private function getTableIndexInItems(Table $table)
    {
        foreach ($this->items as $k => $item) {
            if ($item->table->id == $table->id)
                return $k;
        }

        return -1;
    }

    private function getOrAddTableIndexInItems(Table $table)
    {
        $index = $this->getTableIndexInItems($table);
        if ($index == -1) {

            $item = new OrderBillItem();
            $item->table = $table;
            $this->items[] = $item;
            return count($this->items) - 1;
        }
        return $index;
    }

    public function jsonSerialize(): mixed
    {
        return [
            'items' => $this->items,
            'origin_total_money' => round($this->originTotalMoney, 2),
            'total_money' => round($this->totalMoney, 2),
            'discount_money' => round($this->discountMoney, 2),
            'member' => $this->member,
        ];
    }
}
